package main.constraint;

import java.util.ArrayList;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.StringTokenizer;

import util.Expression;
import util.MathExpression;
import util.ExpressionSet;
import automata.Alphabet;
import automata.Fsa;
import automata.Label;
import automata.State;
import automata.StateSet;
import automata.Transitions;

/**
 * XML Conditional Functional Dependence ---------------------------
 * 
 * This class represents a conditional functional dependence XML with the
 * transformation of path expressions in Finite automata. Thus we have:
 * 
 * xdf = (M, C, (T'-> T"))
 * 
 * where: M is the context path; C is the conditional path; T' is source path or
 * left side; T" is destination path or right side;
 * 
 * @author Eder P. C. Flor
 * @author Aryadne Guardieiro P. Rezende
 */

// @SuppressWarnings("unchecked")
public class XDFC extends ConstraintAbstract {
	private Fsa conditional = new Fsa();
	private ExpressionSet expressionSet = new ExpressionSet();
	
	public XDFC(String name, Fsa f1, Fsa f2, Fsa f3, Fsa f4) {
		nameConstraint = name;
		contextFsa = f1;
		sourceFsa = f2;
		targetFsa = f3;
		conditional = f4;
	}

	public XDFC() {
	}

	/*public void setExpressions(State s, String v)
	{
		double value2 = Double.parseDouble(v);
		Expression e = new Expression()
	}*/
	

	public Fsa pathToFsaCond(String path) throws Exception {
		// System.out.println("Path To FSA: " + path);
		Fsa f = new Fsa();
		int exp = 1;
		int i = 1;
		Label star = new Label("*");
		State start = new State(1); // initial state
		State sant; // previous state
		State s; // ??
		Alphabet alpha = new Alphabet(); // alphabet of Cond
		StateSet ss = new StateSet(); // Set of initial stats?!!!
		StateSet fs = new StateSet(); // Set of final stats
		Transitions t = new Transitions(); // transitions of FSA
		String token = new String();
		MathExpression e = new MathExpression();
		boolean operatorFlag = false; // is true if the anterior simbol is a aritmetic operator
		ss.add(start); // add the initial stat in the set
		sant = start; // the first state will be the anterior state of all the
						// next stats
		StringTokenizer st = new StringTokenizer(path, " "); // the string path
																// wiil be
																// broken
		Exception sintaxErrorException = new Exception("Erro na sintaxe das condicoes. Verifique por favor."); 

		while (st.hasMoreTokens()) // while exist space in the string path
		{
			token = st.nextToken(); // token will be the label of XML document

			if (MathExpression.isMathOperator(token)) {
				//mathOperators.add(token);
				//mathExp++;// number of math expressions increases
				e.setOperator(token);
				operatorFlag = true;
			} else {

				if (token.equals("or") || token.equals("and")) {
					if (!e.setLinkOperator(token))
					{
						throw sintaxErrorException;
					}
					else
					{
						expressionSet.addExpression(sant,e); // add a expression referent of the current state
					}
						
					//logicExp++; // number of logic expressions increases
					//operatorFlag = true;
				}

				else {
					if (token.equals("//"))// indicates that anything can be
											// between the anterior state and
											// the next state - star transition
					{
						alpha.add(star);
						StateSet ss2 = new StateSet();
						ss2.add(sant);
						t.put(sant, star, ss2);
					} else if (operatorFlag) // if the antSimbol is a operator
												// the current simbol is a
												// constant
					{
						e.setConstant(token);//add a constant in to the expression
					}

					else // then, the token is a label
					{
						Label l = new Label(token);
						if (alpha.contains(l)) {
							sant = new State(sant.elt + 1); // one new state is
															// created
						} else {
							i++;
							alpha.add(l);
							s = new State(i);
							ss.add(s);
							StateSet ss1 = new StateSet();
							ss1.add(s);
							t.put(sant, l, ss1);
							sant = s;
						}
					}
					operatorFlag = false;
				}
			}

		}

		fs.add(sant);
		f.set_alphabet(alpha);
		f.set_states(ss);
		f.set_start_state(start);
		f.set_final_states(fs);
		f.set_transitions(t);

		return f;
	}



	/**
	 * Function that creates a path from the context FSA
	 * 
	 * @param s
	 * @return void, but set new context
	 */
	public void setContextFsa(String s) {
		contextFsa = pathToFsa(s);
	}

	/**
	 * Function that creates a path from the source FSA And there you have the
	 * token |
	 * 
	 * @param s
	 * @return void, but set new source
	 */
	public void setSourceFsa(String s) {
		sourceFsa = pathToFsa(s);
		StringTokenizer st = new StringTokenizer(s, " ");
		String token = new String();

		while (st.hasMoreTokens()) {
			token = st.nextToken();
			if (token.equals("|")) {
				npaths++;
			}
		}
		setJ();
	}

	/**
	 * Function that creates a path from the targetFsta
	 * 
	 * @param s
	 * @return void, but set new targetFsa
	 */
	public void setTargetFsa(String s) {
		targetFsa = pathToFsa(s);
	}

	/**
	 * Function that creates FSA (automaton) from a path
	 * 
	 * @param path
	 * @return new FSA
	 */

	public Fsa getConditional() {
		return conditional;
	}

	public void setConditional(String conditional) throws Exception {
		this.conditional = pathToFsaCond(conditional);
	}


	/**
	 * A patir de um FSA sabe qual tipo contextFsa, sourceFsa or targetFsa
	 * 
	 * @param Object
	 *            FSA
	 * @return integer 1 is contextFSA, 2 source FSA or 3 targetFSA
	 */
	public int getFsaPosition(Fsa f) {
		// System.out.print("Define FsaPosition ");
		if (f == contextFsa) {
			// System.out.println("contextFsa");
			return 1;
		}

		if (f == sourceFsa) {
			// System.out.println("sourceFsa left");
			return 2;
		}
		if (f == targetFsa) {
			// System.out.println("targetFsa right");
			return 3;
		}
		if (f == conditional) {
			return 4;
		} else
			return 0;
	}

	public int getNPaths() {
		return npaths;
	}

	public void setNPaths(int n) {
		npaths = n;
	}

	public void setJ() {
		Iterator<State> i = sourceFsa.get_final_states().iterator();

		while (i.hasNext()) {
			j.add(i.next().elt);
		}
	}

	public int getJ(Integer state) {
		return j.indexOf(state);
	}

	public String toString() {
		String str = new String();
		str = "XDFC Name: " + nameConstraint + "\n";
		str += "Fsa Context: " + contextFsa.toString() + "\n";
		str += "Fsa Source: " + sourceFsa.toString() + "\n";
		str += "Fsa Target: " + targetFsa.toString() + "\n";
		str += "Fsa Conditional: " + conditional.toString() + "\n";
		str += "Paths: " + npaths;
		return str;
	}

	public String toStringWeb() {
		String str = new String();
		str = "XDFC Name: " + nameConstraint + "<br>";
		str += "Fsa Context: " + contextFsa.toStringWeb() + "<br>";
		str += "Fsa Source: " + sourceFsa.toStringWeb() + "<br>";
		str += "Fsa Target: " + targetFsa.toStringWeb() + "<br>";
		str += "Fsa Conditional: " + conditional.toStringWeb() + "<br>";
		str += "Paths: " + npaths + "<br>";
		return str;
	}
}
